﻿using System;
using System.Windows.Media.Imaging;
using nRoute.Components.Composition;
using nRoute.ViewServices;
using Orktane.Components;
using Orktane.Sample.ConsoleApp.ViewServices;
using Orktane.ScriptActionModel;

namespace Orktane.Sample.ConsoleApp.ScriptActions
{
    [MapScriptAction("SET-WALLPAPER", "Set Wallpaper", ShortDescription = "Sets the wallpaper on the background.",
        Lifetime = InstanceLifetime.PerInstance)]
    public class SetWallpaperScriptAction 
        : IConsoleScriptAction
    {
        private const string WALLPAPERURL_REQUIRED = "Wallpaper Image Url (png, jpg) must be specified.";
        private const string INVALID_URL = "Invalid Image Url '{0}'.";
        private const string IMAGE_URL_ONLY = "Only png and jpg formats images are supported, '{0}' is not valid image.";
        private const string STARTING_DOWNLOADING = "Starting Download..";
        private const string DOWNLOADED_INFO = "Downloaded {0}%..";
        private const string DOWNLOADED_CANCELLED = "Download cancelled..";
        private const string DOWNLOAD_FAILED = "Download failed..";
        private const string DOWNLOAD_ERROR = "An error occurred while downloading..";
        private const string NO_WALLPAPER_VIEWSERVICE = "Cannot resolve Wallpaper View Service.";
        
        private const string DOT_PNG = ".png";
        private const string DOT_JPEG = ".jpeg";
        private const string DOT_JPG = ".jpg";
        private const string URL_FLAG = "url";

        private BitmapImage _image;
        private IConsole _console;
        private IDisposable _completionToken;
        private Lazy<IWallpaperViewService> _wallpaperViewService;

        [ResolveConstructor]
        public SetWallpaperScriptAction(Lazy<IWallpaperViewService> wallpaperViewService)
        {
            if (wallpaperViewService == null) throw new ArgumentNullException("wallpaperViewService");
            _wallpaperViewService = wallpaperViewService;
        }

#region IConsoleScriptAction Members

        public void Intialize(IConsole console, IDisposable completionToken)
        {
            if (console == null) throw new ArgumentNullException("console");
            if (completionToken == null) throw new ArgumentNullException("completionToken");

            _console = console;
            _completionToken = completionToken;
        }

        public bool Cancel()
        {
            _console.WriteLine(DOWNLOADED_CANCELLED);
            _console.WriteLine();
            return true;
        }

        public void Close()
        {
            _console.DisableInput = false;
            _image = null;
            _console = null;
        }

#endregion

#region IScriptAction Members

        public void Execute(Arguments args)
        {
            // get the url, it can either be -url:http://... or just http://...
            string _imageUrl = null;
            Uri _imageUri;

            if (args != null && args.Exists(URL_FLAG))
            {
                _imageUrl = Convert.ToString(args[URL_FLAG][0]);
            }
            else if (args != null && !string.IsNullOrEmpty(args.CommandLine))
            {
                _imageUrl = args.CommandLine;
            }

            // we parse n' ensure it is supported
            if (string.IsNullOrEmpty(_imageUrl))
            {
                _console.WriteLine(WALLPAPERURL_REQUIRED);
                SetCompleted();
            }
            else if (!Uri.TryCreate(_imageUrl, UriKind.Absolute, out _imageUri))
            {
                _console.WriteLine(INVALID_URL, _imageUrl);
                SetCompleted();
            }
            else if (!ValueEndsWith(_imageUri.LocalPath, DOT_PNG, DOT_JPG, DOT_JPEG))
            {
                _console.WriteLine(IMAGE_URL_ONLY, _imageUrl);
                SetCompleted();
            }
            else
            {
                // we disable input
                _console.DisableInput = true;
                _console.DisabledInputText = STARTING_DOWNLOADING;

                // we download
                _image = new BitmapImage(_imageUri);
                _image.CreateOptions = BitmapCreateOptions.None;
                _image.DownloadProgress += new EventHandler<DownloadProgressEventArgs>(Image_DownloadProgress);
                _image.ImageFailed += new EventHandler<System.Windows.ExceptionRoutedEventArgs>(Image_ImageFailed);
                _image.ImageOpened += new EventHandler<System.Windows.RoutedEventArgs>(Image_ImageOpened);
            }
        }

#endregion

#region Handlers

        private void Image_ImageOpened(object sender, System.Windows.RoutedEventArgs e)
        {
            if (_console == null) return;

            if (_wallpaperViewService.Value == null)
            {
                _console.WriteLine(NO_WALLPAPER_VIEWSERVICE);
            }
            else
            {
               _wallpaperViewService.Value.SetWallpaper(_image);
            }
            
            SetCompleted();
        }

        private void Image_ImageFailed(object sender, System.Windows.ExceptionRoutedEventArgs e)
        {
            if (_console == null) return;

            if (e.ErrorException != null)
            {
                _console.WriteLine(DOWNLOAD_ERROR);
                _console.WriteLine();
                _console.WriteLine(e.ErrorException.ToString());
            }
            else
            {
                _console.WriteLine(DOWNLOAD_FAILED);
            }

            SetCompleted();
        }

        private void Image_DownloadProgress(object sender, DownloadProgressEventArgs e)
        {
            if (_console == null) return;
            _console.DisabledInputText = string.Format(DOWNLOADED_INFO, e.Progress);
        }
        
#endregion

#region Helpers

        private void SetCompleted()
        {
            _completionToken.Dispose();
        }

        private static bool ValueEndsWith(string value, params string[] matchValues)
        {
            foreach(var _value in matchValues) 
                if (value.EndsWith(_value, StringComparison.InvariantCultureIgnoreCase)) return true;
            
            // all else
            return false;
        }

#endregion

    }
}
